package santiago.client;

import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.util.Collection;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.UnsupportedLookAndFeelException;
import santiago.codebase.IClient;
import santiago.codebase.IServer;
import santiago.codebase.NetworkParameter;
import santiago.domain.CardinalPoint;
import santiago.domain.DifficultyLevel;
import santiago.domain.Game;
import santiago.domain.Player;
import santiago.exception.AlreadyInGameException;
import santiago.exception.ExistingItemException;
import santiago.exception.InvalidAmountException;
import santiago.exception.MaximalPlayerCountReachedException;
import santiago.exception.NoSuchGameException;
import santiago.exception.NotEnoughCashException;
import santiago.exception.NotEnoughPlayerException;
import santiago.exception.NotInGameException;
import santiago.server.Server;
import santiago.view.SantiagoFrameManager;

public class Client {

    private static IClient Callback;
    private static IServer Proxy;
    private static String Login;
    private static SantiagoFrameManager Interface;

    public Client() {
        try {
            Interface = new SantiagoFrameManager();
            Callback = new RMIClient();
        } catch (RemoteException ex) {
            ErrorMessage.CallbackInitializationFailed.display();
            throw new UnsupportedOperationException();
        }
    }

    public static void authentication(String Login, String Password) {
        if (true) { //TODO: auth server
            Client.Login = Login;
            Interface.authentication(Login, Password);
            SuccessMessage.Authenticated.display();
        }
    }

    public static void connect(String RemoteIP) {
        try {
            Proxy = (IServer) LocateRegistry.getRegistry(RemoteIP).lookup("//" + RemoteIP + ":" + NetworkParameter.RMI_PORT.getValue() + "/" + NetworkParameter.SERVER_NAME.getValue());
            Proxy.connect(Login, Callback);
            Interface.connect();
            SuccessMessage.Connected.display();
        } catch (RemoteException | NotBoundException | ExistingItemException ex) {
            handleException(ex);
        }
    }

    public static void disconnect() {
        if (Proxy != null) {
            try {
                Proxy.disconnect(getLogin());
                Interface.disconnect(getLogin());
                SuccessMessage.Disconnected.display();
            } catch (RemoteException ex) {
                handleException(ex);
            }
            Proxy = null;
        }
    }

    public static void main(String[] args) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                new Server();
            }
        }).start();

        for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) {
            if ("Nimbus".equals(info.getName())) {
                try {
                    javax.swing.UIManager.setLookAndFeel(info.getClassName());
                    break;
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    Logger.getLogger(Client.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
        }
        new Client();
        //Test only: remove later
        authentication("" + (int) (Math.random() * 100000), null);
        Interface.joinServer();
    }

    public static void createGame(String GameName, int PlayerNbr, DifficultyLevel Level, boolean DisplayCash, boolean PalmTree) {
        try {
            Proxy.createGame(GameName, PlayerNbr, Level, DisplayCash, PalmTree);
            Interface.createGameConfirm();
            joinGame(GameName);
            SuccessMessage.CreatedGame.display();
        } catch (RemoteException | ExistingItemException ex) {
            handleException(ex);
        }
    }

    public static void joinGame(String GameName) {
        try {
            Proxy.joinGame(GameName, getLogin());
            Interface.joinGame(GameName);
            SuccessMessage.JoinedGame.display();
        } catch (RemoteException | ExistingItemException | MaximalPlayerCountReachedException | AlreadyInGameException | NoSuchGameException | NotEnoughPlayerException ex) {
            handleException(ex);
        }
    }

    public static void leaveGame() {
        try {
            Proxy.leaveGame(getLogin(), getGameName());
            Interface.leaveGame();
            SuccessMessage.LeaveGame.display();
        } catch (RemoteException | NoSuchGameException ex) {
            handleException(ex);
        }
    }

    public static void sendMessage(String Message) {
        try {
            Proxy.sendMessage(Login, Message);
        } catch (RemoteException ex) {
            handleException(ex);
        }
    }

    public static void bid(int Amount) {
        try {
            Proxy.bid(Login, Amount);
        } catch (RemoteException | InvalidAmountException | NotEnoughCashException ex) {
            handleException(ex);
        }
    }

    public static void placePlantation(int NodeIndex, int PlantationIndex, CardinalPoint Location) {
        try {
            Proxy.placePlantation(Login, NodeIndex, PlantationIndex, Location);
        } catch (RemoteException ex) {
            handleException(ex);
        }
    }

    public static SantiagoFrameManager getInterface() {
        return Interface;
    }

    public static String getLogin() {
        return Login;
    }

    public static String getGameName() {
        try {
            return getPlayer().getGameName();
        } catch (NotInGameException ex) {
            handleException(ex);
        }
        return null;
    }

    public static Game getGame() {
        try {
            return Proxy.getGame(getGameName());
        } catch (RemoteException ex) {
            handleException(ex);
        }
        return null;
    }

    public static Set<Game> getGames() {
        try {
            return Proxy.getGames();
        } catch (RemoteException ex) {
            handleException(ex);
        }
        return null;
    }

    public static Player getPlayer() {
        try {
            return Proxy.getPlayer(Login);
        } catch (RemoteException ex) {
            handleException(ex);
        }
        return null;
    }

    public static Collection<Player> getPlayers() {
        return getGame().getPlayers();
    }

    public static void handleException(Exception e) {
        Logger.getLogger(Client.class.getName()).log(Level.SEVERE, null, e);

        switch (e.getClass().getName()) {
            case "RemoteException":
            case "AlreadyInGameException":
            case "ExistingItemException":
            case "MaximalPlayerCountReachedException":
            case "NoSuchGameException":
            case "NotInGameException":
            case "NotBoundException":
            case "AccessException":
            case "NotEnoughPlayerException":
            default:
                Interface.handleException(e);
        }
    }
}
